﻿using System.Reflection;

namespace Devonline.AspNetCore
{
    /// <summary>
    /// 排序选项
    /// 排序方式只判断是否 desc 字样
    /// </summary>
    public class OrderbyOption
    {
        /// <summary>
        /// 逆向排序比较字符串
        /// </summary>
        private const string ORDERBY_DESC = "desc";
        /// <summary>
        /// 当前排序对象的排序值字符串表示形式
        /// </summary>
        private readonly string? _orderby;
        /// <summary>
        /// 当前表达式的类型主体
        /// </summary>
        private readonly Type? _type;

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public OrderbyOption()
        {
        }
        /// <summary>
        /// 从排序字符串递归获取排序方式
        /// 原始输入字符串样式如下:
        /// Id, Name asc, Age desc
        /// </summary>
        /// <param name="orderby"></param>
        public OrderbyOption(Type type, string orderby)
        {
            _type = type;
            var index = orderby.IndexOf(AppSettings.CHAR_COMMA);
            if (index > 0)
            {
                _orderby = orderby[0..(index - 1)];
                Then = new OrderbyOption(type, orderby[index..]);
            }
            else
            {
                _orderby = orderby;
            }

            if (index != 0)
            {
                //_orderby is not AppSettings.CHAR_COMMA, then
                var orderbys = _orderby.Split(AppSettings.CHAR_SPACE, StringSplitOptions.RemoveEmptyEntries);
                if (orderbys.Length > 0)
                {
                    Field = orderbys[0];
                    if (_type.GetMember(Field).IsNullOrEmpty())
                    {
                        throw new ArgumentException($"the property or field {Field} of type {_type.Name} not found!");
                    }
                }

                Asc = true;
                if (orderbys.Length > 1)
                {
                    Asc = orderbys[1].ToUpperInvariant() != ORDERBY_DESC.ToUpperInvariant();
                }
            }
        }

        /// <summary>
        /// 当前排序字段
        /// </summary>
        public string? Field { get; set; }
        /// <summary>
        /// 是否顺序
        /// </summary>
        public bool Asc { get; set; }
        /// <summary>
        /// 下一个排序字段
        /// </summary>
        public OrderbyOption? Then { get; set; }

        /// <summary>
        /// 重写的 ToString 方法来输出字符形式的 orderby 表达式
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            var result = Field;
            if (!Asc)
            {
                result += AppSettings.CHAR_SPACE + ORDERBY_DESC;
            }

            if (Then != null)
            {
                result += AppSettings.CHAR_COMMA + AppSettings.CHAR_SPACE + Then.ToString();
            }

            return result ?? string.Empty;
        }
    }

    /// <summary>
    /// 排序选项
    /// 排序方式只判断是否 desc 字样
    /// </summary>
    public class OrderbyOption<T>
    {
        /// <summary>
        /// 逆向排序比较字符串
        /// </summary>
        private const string ORDERBY_DESC = "desc";
        /// <summary>
        /// 当前排序对象的排序值字符串表示形式
        /// </summary>
        private readonly string? _orderby;
        /// <summary>
        /// 当前表达式的类型主体
        /// </summary>
        private readonly Type? _type = typeof(T);

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public OrderbyOption()
        {
        }
        /// <summary>
        /// 从排序字符串递归获取排序方式
        /// 原始输入字符串样式如下:
        /// Id, Name asc, Age desc
        /// </summary>
        /// <param name="orderby"></param>
        public OrderbyOption(string orderby)
        {
            var index = orderby.IndexOf(AppSettings.CHAR_COMMA);
            if (index > 0)
            {
                _orderby = orderby[0..(index - 1)];
                Then = new OrderbyOption<T>(orderby[index..]);
            }
            else
            {
                _orderby = orderby;
            }

            if (index != 0)
            {
                //_orderby is not AppSettings.CHAR_COMMA, then
                var orderbys = _orderby.Split(AppSettings.CHAR_SPACE, StringSplitOptions.RemoveEmptyEntries);
                if (orderbys.Length > 0)
                {
                    Field = orderbys[0];
                    if (_type.GetMember(Field, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase).IsNullOrEmpty())
                    {
                        throw new ArgumentException($"the property or field {Field} of type {_type.Name} not found!");
                    }
                }

                Asc = true;
                if (orderbys.Length > 1)
                {
                    Asc = orderbys[1].ToUpperInvariant() != ORDERBY_DESC.ToUpperInvariant();
                }
            }
        }

        /// <summary>
        /// 当前排序字段
        /// </summary>
        public string? Field { get; set; }
        /// <summary>
        /// 是否顺序
        /// </summary>
        public bool Asc { get; set; }
        /// <summary>
        /// 下一个排序字段
        /// </summary>
        public OrderbyOption<T>? Then { get; set; }

        /// <summary>
        /// 重写的 ToString 方法来输出字符形式的 orderby 表达式
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            var result = Field;
            if (!Asc)
            {
                result += AppSettings.CHAR_SPACE + ORDERBY_DESC;
            }

            if (Then != null)
            {
                result += AppSettings.CHAR_COMMA + AppSettings.CHAR_SPACE + Then.ToString();
            }

            return result ?? string.Empty;
        }
    }
}
